package com.mp.approvalreq.dao.impl;

import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.dao.ComponentDao;
import com.mp.approvalreq.entity.GroupContent;
import com.mp.approvalreq.entity.Leave;
import com.mp.approvalreq.entity.Outdoor;
import com.mp.approvalreq.entity.TemplateComponent;
import com.mp.approvalreq.util.ObjectUtils;
import com.plusmoney.util.DateTimeHelper;
import com.plusmoney.util.SQLLogger;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;


public class ComponentImpl extends AbstractDao implements ComponentDao {

    private static final Logger logger = LoggerFactory.getLogger(ComponentImpl.class);

    private Connection connection;

    public ComponentImpl(Connection connection) {
        this.connection = connection;
    }

    private PreparedStatement getPreparedStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }

    @Override
    String getQuerySql(String condition) {
        final String query = "select Fid, Ftemplate_id, Fcomponent_num, Fcontent, Frequest_id,"
                + " Fcontent_type, Fsort"
                + " from request_content";
        return String.format("%s %s", query, condition);
    }

    @Override
    TemplateComponent getObject(ResultSet rs) throws SQLException {
        TemplateComponent component = new TemplateComponent();
        component.setDbkey(rs.getInt(1));
        component.setTemplateId(rs.getInt(2));
        component.setNum(rs.getInt(3));
        component.setValue(rs.getString(4));
        component.setRequestId(rs.getInt(5));
        component.setType(rs.getInt(6));
        component.setSort(rs.getInt(7));
        return component;
    }


    @Override
    public List<TemplateComponent> selectComponentByRequestId(Integer requestId) throws SQLException {
        List<TemplateComponent> list = new ArrayList<>();
        String sql = getQuerySql("where Frequest_id = ?");

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            ps.setInt(1, requestId);
            logger.info(SQLLogger.logSQL(sql, requestId));

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    list.add(getObject(rs));
                }
            }
        }
        return list;
    }

    @Override
    public Map<Integer, List<TemplateComponent>> selectComponentMapByRequestIds(String requestIds) throws SQLException {
        Map<Integer, List<TemplateComponent>> map = new HashMap<>();
        if (StringUtils.isEmpty(requestIds)) {
            return map;
        }
        String sql = getQuerySql("where Frequest_id in(" + requestIds + ")");

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            logger.info(sql);

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    TemplateComponent component = getObject(rs);
                    if (!map.containsKey(component.getRequestId())) {
                        map.put(component.getRequestId(), new ArrayList<>());
                    }
                    map.get(component.getRequestId()).add(component);
                }
            }
        }
        return map;
    }

    @Override
    public void insertBatchComponent(List<TemplateComponent> components) throws SQLException {
        String sql = "insert into request_content set"
                + " Fid = ?, Ftemplate_id = ?, Fcomponent_num = ?,  Fcontent = ?, Frequest_id = ?,"
                + " Fcontent_type = ?, Fsort = ?, Fcompany_id = ?, Fcreate_time = now() ";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            for (TemplateComponent component : components) {
                ObjectUtils.initInteger(component);
                ps.setInt(1, component.getDbkey());
                ps.setInt(2, component.getTemplateId());
                ps.setInt(3, component.getNum());
                ps.setString(4, component.getValue());
                ps.setInt(5, component.getRequestId());
                ps.setInt(6, component.getType());
                ps.setInt(7, component.getSort());
                ps.setInt(8, component.getCompanyId());
                logger.info(SQLLogger.logSQL(sql, component.getDbkey(), component.getTemplateId(), component.getNum(),
                        component.getValue(), component.getRequestId(), component.getType(), component.getSort(), component.getCompanyId()));

                ps.addBatch();
            }
            ps.executeBatch();
        }
    }

    @Override
    public void insertBatchGroupComponent(List<TemplateComponent> components) throws SQLException {
        String sql = "insert into sys_approval_component_group_value set"
                + " company_id = ?, request_id = ?, content_num = ?, component_group_id = ?, sort = ?,"
                + " value = ?, create_time = now()";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            for (TemplateComponent component : components) {
                ObjectUtils.initInteger(component);
                for (GroupContent groupContent : component.getGroupContents()) {
                    ObjectUtils.initInteger(groupContent);
                    ps.setInt(1, component.getCompanyId());
                    ps.setInt(2, component.getRequestId());
                    ps.setInt(3, component.getNum());
                    ps.setInt(4, component.getGroupId());
                    ps.setInt(5, groupContent.getSort());

                    String value = JSONObject.toJSONString(groupContent.getValue());
                    ps.setString(6, value);
                    logger.info(SQLLogger.logSQL(sql, component.getCompanyId(), component.getRequestId(), component.getNum(), component.getGroupId(),
                            groupContent.getSort(), value));

                    ps.addBatch();
                }
            }
            ps.executeBatch();
        }
    }

    @Override
    public Map<Integer, List<GroupContent>> selectGroupComponentByRequestId(Integer requestId) throws SQLException {
        Map<Integer, List<GroupContent>> map = new LinkedHashMap<>();
        String sql = "select content_num, sort, value from"
                + " sys_approval_component_group_value"
                + " where request_id = ? order by content_num, sort";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            ps.setInt(1, requestId);
            logger.info(SQLLogger.logSQL(sql, requestId));

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    int num = rs.getInt(1);
                    GroupContent groupContent = new GroupContent();
                    groupContent.setSort(rs.getInt(2));
                    groupContent.setValue(rs.getString(3));

                    if (!map.containsKey(num)) {
                        map.put(num, new ArrayList<>());
                    }
                    map.get(num).add(groupContent);
                }
            }
        }
        return map;
    }

    @Override
    public Map<Integer, Map<Integer, List<GroupContent>>> selectGroupComponentByRequestIds(String requestIds) throws SQLException {
        Map<Integer, Map<Integer, List<GroupContent>>> map = new LinkedHashMap<>();
        if (StringUtils.isBlank(requestIds)) {
            return map;
        }
        String sql = "select request_id, content_num, sort, value from"
                + " sys_approval_component_group_value"
                + " where request_id in(" + requestIds + ") order by request_id, content_num, sort";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            logger.info(SQLLogger.logSQL(sql));

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    int requestId = rs.getInt(1);
                    int num = rs.getInt(2);
                    GroupContent groupContent = new GroupContent();
                    groupContent.setSort(rs.getInt(3));
                    groupContent.setValue(rs.getString(4));

                    if (!map.containsKey(requestId)) {
                        map.put(requestId, new LinkedHashMap<>());
                    }
                    Map<Integer, List<GroupContent>> subMap = map.get(requestId);

                    if (!subMap.containsKey(num)) {
                        subMap.put(num, new ArrayList<>());
                    }
                    subMap.get(num).add(groupContent);
                }
            }
        }
        return map;
    }

    @Override
    public void updateOutdoorEndTimeComponent(Outdoor outdoor, Integer timeNum) throws SQLException {
        String sql = "update request_content set Fcontent = ?"
                + " where Frequest_id = ? and Fcomponent_num = ? limit 1";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            String endTime = DateTimeHelper.format(outdoor.getEnd(), DateTimeHelper.YEAR_MONTH_DAY_HOUR_MINUTE_PATTERN);
            ps.setString(1, endTime);
            ps.setInt(2, outdoor.getRequestId());
            ps.setInt(3, timeNum);
            logger.info(SQLLogger.logSQL(sql, endTime, outdoor.getRequestId(), timeNum));

            ps.executeUpdate();
        }
    }

    @Override
    public void updateBatchComponentValue(List<TemplateComponent> components) throws SQLException {
        String sql = "update request_content set Fcontent = ? where Fid = ? limit 1";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            for (TemplateComponent component : components) {
                ps.setString(1, component.getValue());
                ps.setInt(2, component.getDbkey());
                logger.info(SQLLogger.logSQL(sql, component.getValue(), component.getDbkey()));

                ps.addBatch();
            }
            ps.executeBatch();
        }
    }

    @Override
    public void updateDaysOffComponent(Leave leave) throws SQLException {
        String sql = "update request_content set Fcontent = ?"
                + " where Frequest_id = ? and Fcomponent_num = 4 limit 1";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            ps.setString(1, leave.getLeaveTimeDetail());
            ps.setInt(2, leave.getRequestId());
            logger.info(SQLLogger.logSQL(sql, leave.getLeaveTimeDetail(), leave.getRequestId()));

            ps.executeUpdate();
        }
    }

    @Override
    public void updateContent(String content, Integer requestId, Integer num, Integer type) throws SQLException {
        String sql = " update request_content set Fcontent = ? " +
                " where Frequest_id = ? and Fcomponent_num = ? and Fcontent_type = ? limit 1";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            ps.setString(1, content);
            ps.setInt(2, requestId);
            ps.setInt(3, num);
            ps.setInt(4, type);
            logger.info(SQLLogger.logSQL(sql, content, requestId, num, type));

            ps.executeUpdate();
        }
    }
}
